<--- %%NOBANNER%% --> univ.sas
 BackForward

/*-------------------------------------------------------------------------------\
| SOURCE:   univ.sas                                                             |
|                                                                                |
| VERSION:  RDS v3.0                                                             |
|                                                                                |
| PURPOSE:  This macro completes a statistical analysis of many variables and    |
|           prints the output on one page.  Basically, it is a PROC UNIVARIATE   |
|           with an output that looks like PROC MEANS.                           |
|                                                                                |
| SYNTAX:   %univ (indata   = _dataset_name_,                          |
|                  outdata    = _output_dataset_,                      |
|                  var    = _variable_list_,                           |
|                  round  = _rounding_descriptor_,                     |
|                  by     = _by_variable_,                             |
|                  stats  = _statistics_to_print_)                     |
\-------------------------------------------------------------------------------*/
%macro univ(indata=, var=, outdata=contents, round=.01, by=, stats=_STD_) / des='Univariate statistics on one page';
%let notes=%sysfunc(getoption(notes, keyword));

options nonotes;
%let starttime=%sysfunc(datetime());
%local i dataset v round by bye pageby var fn stats bn lb;

/*----------------\
| assign defaults |
\----------------*/
%let the_end = N;

%if (%quote(&indata) = %quote()) %then %do;
   %let indata = %upcase(%scan(&sysdsn, 1).%scan(&sysdsn, 2));
   options ¬es;
   %put NOTE: No datasets are specified.  The dataset &indata will be used.;
   options nonotes;
%end;
%else %let indata = %data(&indata);

%if (%quote(&var) = %quote()) %then %do;
   proc contents data=&indata out=contents(keep=name type) noprint; run;
   data _null_;
      set contents (where = (type=1));
      call symput ('var'||trim(left(_n_)), trim(left(name)));
      call symput ('fn', trim(left(_n_)));
   run;
   %do i = 1 %to &fn;
      %let var = &var &&var&i;
   %end;
%end;
%else %let fn = %wordcnt(&var);

/*------------------------------------------------------------\
| Calculate value of BY and PAGEBY--if by value is not %str() |
\------------------------------------------------------------*/
%if (%quote(&by) ne %quote()) %then %do;
   %let bn     = %words(&by);
   %let lb     = %scan(&by, &bn, %str( ));
   %let pageby = %str(pageby &lb ;);
   %let bye    = %str(by &by ;);
%end;

/*--------------------------------------------\
| If keywards are not used in the macro call, |
| this section assigns keywords based on      |
| option _STD_ (standard) or _ALL_ (all).     |
\--------------------------------------------*/
%if %upcase(&stats) = _STD_ %then %let stats = n mean std cv sum min p10 p25 p50 p75 p90 max;
%else %if %upcase(&stats) = _ALL_ %then 
   %let stats = n nobs nmiss mean mode sum std cv css uss qrange
                msign normal stdmean probn probm probs signrank t
                kurtosis skewness range qrange sumwgt min p1 p5 p10
                p25 p50 p75 p90 p95 p99 max;

/*-------------------------------------\
| Use PROC CONTENTS to get label names |
\-------------------------------------*/
proc contents data=&indata(keep=&var &by) out=contents(keep=name label) noprint; run;

%let data_id = %sysfunc(open(&indata, i));
%do I = 1 %to &fn;
   %let label&i = %sysfunc(varlabel(&data_id, %sysfunc(varnum(&data_id, %scan(&var, &i, %str( ))))));
%end;
%let rc = %sysfunc(close(&data_id));

/*-------------------------------------------------\
| Univariate step writes out to dataset macro.temp |
\-------------------------------------------------*/
proc univariate data=&indata noprint; &bye var &var;
   output out      = temp
          n        = %_prefix(prefix=n,     from=1, to=&FN)
          mean     = %_prefix(prefix=mean,  from=1, to=&FN)
          std      = %_prefix(prefix=std,   from=1, to=&FN)
          cv       = %_prefix(prefix=cv,    from=1, to=&FN)
          min      = %_prefix(prefix=min,   from=1, to=&FN)
          p1       = %_prefix(prefix=p1_,   from=1, to=&FN)
          p5       = %_prefix(prefix=p5_,   from=1, to=&FN)
          p10      = %_prefix(prefix=p10_,  from=1, to=&FN)
          q1       = %_prefix(prefix=p25_,  from=1, to=&FN)
          median   = %_prefix(prefix=p50_,  from=1, to=&FN)
          q3       = %_prefix(prefix=p75_,  from=1, to=&FN)
          p90      = %_prefix(prefix=p90_,  from=1, to=&FN)
          p95      = %_prefix(prefix=p95_,  from=1, to=&FN)
          p99      = %_prefix(prefix=p99_,  from=1, to=&FN)
          max      = %_prefix(prefix=max,   from=1, to=&FN)
          sum      = %_prefix(prefix=sum,   from=1, to=&FN)
          kurtosis = %_prefix(prefix=kurt,  from=1, to=&FN)
          skewness = %_prefix(prefix=skew,  from=1, to=&FN)
          css      = %_prefix(prefix=css,   from=1, to=&FN)
          nmiss    = %_prefix(prefix=nmiss, from=1, to=&FN)
          msign    = %_prefix(prefix=msign, from=1, to=&FN)
          nobs     = %_prefix(prefix=nobs,  from=1, to=&FN)
          qrange   = %_prefix(prefix=qrang, from=1, to=&FN)
          t        = %_prefix(prefix=t,     from=1, to=&FN)
          normal   = %_prefix(prefix=norm,  from=1, to=&FN)
          sumwgt   = %_prefix(prefix=sumwt, from=1, to=&FN)
          stdmean  = %_prefix(prefix=stdmn, from=1, to=&FN)
          probn    = %_prefix(prefix=probn, from=1, to=&FN)
          range    = %_prefix(prefix=range, from=1, to=&FN)
          var      = %_prefix(prefix=var,   from=1, to=&FN)
          probm    = %_prefix(prefix=probm, from=1, to=&FN)
          mode     = %_prefix(prefix=mode,  from=1, to=&FN)
          signrank = %_prefix(prefix=sign,  from=1, to=&FN)
          uss      = %_prefix(prefix=uss,   from=1, to=&FN)
          probs    = %_prefix(prefix=probs, from=1, to=&FN) ;
run ;
/*--------------------------------------------------------------\
| transpose the dataset macro.temp to be printed, round values, |
| add labels, format the label descriptor, and keep variables   |
\--------------------------------------------------------------*/
data &outdata (keep = varname label min p1 p5 p10 p25 p50 p75 p90 p95
               p99 max kurtosis n skewness css nmiss std msign mean nobs 
               sum qrange t normal sumwgt stdmean probn range cv probm 
               mode signrank uss probs &by);
   set temp;
   label label    = 'Variable description'
         varname  = 'Variable name'
         n        = 'Number non-missing values'
         mean     = 'Mean value'
         sum      = 'Sum of all values'
         std      = 'Standard deviation'
         cv       = 'Coefficient of variation'
         min      = 'Minimum value'
         p1       = '1st %tile'
         p5       = '5th %tile'
         p10      = '10th %tile'
         p25      = '25th %tile'
         p50      = '50th %tile'
         p75      = '75th %tile'
         p90      = '90th %tile'
         p95      = '95th %tile'
         p99      = '99th %tile'
         max      = 'Maximum value'
         kurtosis = 'Kurtosis'
         skewness = 'Skewness'
         css      = 'Corrected sum of squares'
         nmiss    = 'Number missing values'
         msign    = 'Sign statistic'
         nobs     = 'Number observations'
         qrange   = 'Inter-quartile range'
         T        = "Student's T"
         normal   = 'Normality test statistic'
         sumwgt   = 'Sum of the weights'
         stdmean  = 'Standard mean'
         probn    = 'P-value of normality test statistic'
         range    = 'Range of values'
         var      = 'Variance'
         probm    = 'P-value of sign statistic'
         mode     = 'Most frequent value'
         signrank = 'Signed Rank Statistic'
         uss      = 'Uncorrected sum of squares'
         probs    = 'P-value of signed ranked statistic' ;
   length label $40 varname $8 ;
   /*------------------------------------\
   | This section mimmics PROC TRANSPOSE |
   \------------------------------------*/
   %do I = 1 %to &fn;
      varname  = "%scan(&var, &i, %str( ))";
      label    = "&&label&i";
      if label = '' then label = left(varname);
      n        = n&i;
      mean     = round(mean&i,  &round);
      sum      = round(sum&i,   &round);
      std      = round(std&i,   &round);
      cv       = round(cv&i,    &round);
      min      = round(min&i,   &round);
      P1       = round(P1_&i,   &round);
      P5       = round(P5_&i,   &round);
      P10      = round(P10_&i,  &round);
      P25      = round(P25_&i,  &round);
      P50      = round(P50_&i,  &round);
      P75      = round(P75_&i,  &round);
      P90      = round(P90_&i,  &round);
      P95      = round(P95_&i,  &round);
      P99      = round(P99_&i,  &round);
      max      = round(max&i,   &round);
      kurtosis = round(kurt&i,  &round);
      skewness = round(skew&i,  &round);
      css      = round(css&i,   &round);
      nmiss    = round(nmiss&i, &round);
      msign    = round(msign&i, &round);
      nobs     = round(nobs&i,  &round);
      qrange   = round(qrang&i, &round);
      T        = round(T&i,     &round);
      normal   = round(norm&i,  &round);
      sumwgt   = round(sumwt&i, &round);
      stdmean  = round(stdmn&i, &round);
      probn    = round(probn&i, &round);
      range    = round(range&i, &round);
      var      = round(var&i,   &round);
      probm    = round(probm&i, &round);
      mode     = round(mode&i,  &round);
      signrank = round(sign&i,  &round);
      uss      = round(uss&i,   &round);
      probs    = round(probs&i, &round);
      output ;
   %end;
run;

/*------------------------------------------------------\
| If by-variables are used, sort the transposed dataset |
\------------------------------------------------------*/
%if &by ne %str() %then %do ;
   proc sort data=&outdata; by &by; run;
%end ;

/*-----------------------------------\
| PROC PRINT is used to print output |
\-----------------------------------*/
proc print data=&outdata noobs label; &bye &pageby id varname; var label &stats; run;

/*-----------------------------------------\
| Delete temporary datasets and data views |
\-----------------------------------------*/
proc datasets lib=macro nolist memtype=(data view); delete contents view1 temp; run; quit;

/*--------------------------------------\
| Prepare the SAS session for open code |
\--------------------------------------*/
%put NOTE: Macro UNIV printed statistics for variabes %upcase(&var).;

%if (%quote(%upcase(&outdata)) ne %quote(CONTENTS)) %then %do ;
   %let outobs = %nobs(&outdata);
   %let outvar = %nvars(&outdata);
   options ¬es;
   %put NOTE: The dataset %data(&outdata) has &outobs observations and &outvar variables.;
   options nonotes;
%end ;
%timenote (macro=univ,starttime=&starttime)
options ¬es;
%mend univ;